<?php

abstract class Model
{
	/**
	 * ID of the row in the database
	 * an ID of 0 is considered a new row to be inserted
	 *
	 * @var int
	 */
	protected $id;
	
	
	/**
	 * Name/value pairs for the row in the databse
	 *
	 * @var array
	 */
	public $fields = array();
	
	/**
	 * 
	 * @var unknown_type
	 */
	private $table;
	
	/**
	 * 
	 * Enter description here ...
	 * @param array $where
	 * @param string $orderBy
	 * @param string $dir
	 * @param int $limit
	 * @return array
	 */
	public static function getAll($where = array(), $orderBy = null, $dir = 'ASC', $limit = 0)
	{
		return self::getAllModels(get_called_class(), $where, $orderBy, $dir, $limit);
	}
	
	/**
	 * 
	 * Enter description here ...
	 * @param int $id
	 */
	public function __construct($id = 0)
	{
		if($id > 0)
		{
			$this->id = $id;
			$this->getData();
		}
	}
	
	/**
	 * @return int
	 * Enter description here ...
	 */
	public function getId()
	{
		return $this->id;	
	}
	
	public function getTable()
	{
		if(!$this->table)
		{
			$this->table = get_class($this);
		}
		return $this->table;
	}
	
	/**
	 * 
	 * Enter description here ...
	 * @return bool
	 */
	public function exists()
	{
		$count = Database::select_count($this->getTable(), array('id' => $this->getId()));
		return $count > 0;
	}	
	
	protected function getData()
	{		
		Database::select_row_by_id($this->getTable(), $this->id);
		$this->fields = Database::select_row_by_id($this->getTable(), $this->id);		 		
	}
	
	public function setData(array $data)
	{
		$this->fields = $data;
	}
	
	public function __set($field, $value)
	{
		$this->fields[$field] = $value;
	}
	
	/**
	 *
	 * @param string $field
	 * @return unknown
	 */
	public function __get($field)
	{
		if(!key_exists($field, $this->fields))
		{
			if(DTAP == "D" || DTAP == "T")
			{
				throw new Exception("'".$field."' not set in ".get_class($this));				
			}
			return null;
			
		}
		return $this->fields[$field];
	}
	
	public function getFieldData()
	{
		return $this->fields;
	}
	
	public function getTableStructure()
	{
		return Database::getTableStructure($this->getTable());
	}
	
	public function add()
	{
		$fields = $this->fields;		
		unset($fields['id']);
		$this->id = Database::insert_row($this->getTable(), $fields);		
	}
	
	public function update()
	{
		$fields = $this->fields;
		if($this->id == 0 && $fields['id'] != 0)
		{
			$this->id = $fields['id'];
		}		
		unset($fields['id']);
		Database::update_row($this->getTable(), $this->id, $fields);		
	}
	
	/**
	 * Save the row into the database (updates if id > 0)
	 *
	 */
	public function save()
	{
		if($this->id == 0)
		{
			$this->add();
		}
		else
		{
			$this->update();
		}
	}
	
	public function delete()
	{
		if($this->id > 0)
		{
			Database::delete_row($this->getTable(), $this->id);
		}
	}	
		
	/**
	 * 
	 * @param string $class
	 * @param array $where
	 * @param string $orderBy
	 * @param string $dir
	 * @return Model
	 */
	public static function getAllModels($class, $where = array(), $orderBy = null, $dir = 'ASC', $limit = 0)
	{		
		$rows = Database::select_rows($class, $where, $orderBy, $dir, $limit);
		$instances = array();
		foreach ($rows as $row)
		{
			$instances[] = new $class($row['id']);
		}
		return $instances;
	}
		
	/**
	 * 
	 * @param string $class
	 * @param array $where
	 * @param string $orderBy
	 * @param string $dir
	 * @return Model
	 */
	protected static function getSingleModel($class, $where = array(), $orderBy = null, $dir = 'ASC')
	{		
		$instances = self::getAllModels($class, $where, $orderBy, $dir, 1);
		return $instances[0];
	}
	/**
	 * 
	 * @param array $where
	 * @param string $orderBy
	 * @param string $dir
	 * @return Model
	 */
	public static function getSingle($where = array(), $orderBy = null, $dir = 'ASC')
	{		
		return self::getSingleModel(get_called_class(), $where, $orderBy, $dir);
	}
	
	
	public static function getAllFromQuery($query)
	{		
		$class = get_called_class();
		$result = Database::query($query);
		$rows = Database::convertResult($result);
		$instances = array();
		foreach ($rows as $row)
		{
			$instances[] = new $class($row['id']);
		}
		return $instances;
	}
}